import processing.core.*; import java.applet.*; import java.awt.*; import java.awt.image.*; import java.awt.event.*; import java.io.*; import java.net.*; import java.text.*; import java.util.*; import java.util.zip.*; public class p5tetris extends PApplet {int [] blk_colors = {
  color(255,255,255),
  color(0,255,255),
  color(240,240,0),
  color(0,255,0),
  color(255,0,0),
  color(0,0,255),
  color(255,90,16),
  color(255,0,255)};
int [] blk_shape_I = {
  0,1,0,0,
  0,1,0,0,
  0,1,0,0,
  0,1,0,0};
int [] blk_shape_O = {
  0,0,0,0,
  0,1,1,0,
  0,1,1,0,
  0,0,0,0};
int [] blk_shape_S = {
  0,0,0,0,
  0,0,1,1,
  0,1,1,0,
  0,0,0,0};
int [] blk_shape_Z = {
  0,0,0,0,
  1,1,0,0,
  0,1,1,0,
  0,0,0,0};
int [] blk_shape_J = {
  0,0,1,0,
  0,0,1,0,
  0,1,1,0,
  0,0,0,0};
int [] blk_shape_L = {
  0,1,0,0,
  0,1,0,0,
  0,1,1,0,
  0,0,0,0};
int [] blk_shape_T = {
  0,0,0,0,
  1,1,1,0,
  0,1,0,0,
  0,0,0,0};
int [] blk_start_at = {
  0,-1,-1,-1,0,0,-1};
int [][][] blk_shapes = new int[7][4][16];
int width = 10;
int height = 18;
int [][] grid = new int[height][width];
int blk_x = 0;
int blk_y = 0;
int blk_r = 0;
int blk_shape = 0;
int next_blk_shape = PApplet.parseInt(random(7));
int grid_size = 30;
int display_height = grid_size * 19;
int display_width = grid_size * 16;
int duration = 0;
boolean Gameover = false;
int [][][] particle = new int[height][width][5];
int [][][] particlen = new int[4][4][5];

public void setup()
{
  size(480,570);
  noSmooth();
  colorMode(RGB,255);
  rectMode(CORNER);
  frameRate(15);
  for (int j = 0; j < height; j++) {
    for (int i = 0; i < width; i++) {
      grid[j][i] = 0;
    };
  };
  init_blk_shapes();
  init_particles();
  background(255);
  shift();
  move(0,1,0);
}

public void draw()
{
  if (Gameover) {
    background(255);
    draw_particles();
  } 
  else {
    for (int j = 0; j < height; j++) {
      for (int i = 0; i < width; i++) {
	fill(blk_colors[grid[j][i]]);
	rect(i * grid_size, j * grid_size, grid_size, grid_size);
      };
    };
    fill(blk_colors[blk_shape + 1]);
    for (int i = 0; i < 16; i++) {
      if (blk_shapes[blk_shape][blk_r][i] == 1) {
        rect((blk_x + (i % 4)) * grid_size, (blk_y + (i / 4)) * grid_size + duration, grid_size, grid_size);
      };
    };
    duration += (grid_size / 5);
    if (duration == grid_size) {
      move(0,1,0);
      duration = 0;
    };
  };
}

public boolean can_move(int dx, int dy, int dr)
{
  int new_x = blk_x + dx;
  int new_y = blk_y + dy;
  int new_r = (blk_r + dr) % 4;
  for (int i = 0; i < 16; i++) {
    if (blk_shapes[blk_shape][new_r][i] == 1) {
      int cx = new_x + (i % 4);
      int cy = new_y + (i / 4);
      if ((((cx < 0) || (cx >= width)) ||
        ((cy < 0) || (cy >= height))) ||
        (grid[cy][cx] != 0)) {
        return false;
      };
    };
  };
  return true;
}

public void move(int dx, int dy, int dr)
{
  if (can_move(dx, dy, dr)) {
    blk_x += dx;
    blk_y += dy;
    blk_r = (blk_r + dr) % 4;
  };
  if (!can_move(0,1,0)) {
    for (int i = 0; i < 16; i++) {
      if (blk_shapes[blk_shape][blk_r][i] == 1) {
        int cx = blk_x + (i % 4);
        int cy = blk_y + (i / 4);
        grid[cy][cx] = blk_shape + 1;
      };
    };
    remove_complete();
    if ((grid[0][4] != 0) || (grid[0][5] != 0)) {
      Gameover = true;
    } 
    else {
      shift();
    };
  };
}

public void shift()
{
  blk_x = 3;
  blk_r = 0;
  blk_shape = next_blk_shape;
  blk_y = blk_start_at[blk_shape];
  next_blk_shape = PApplet.parseInt(random(7));
  for (int i = 0; i < 16; i++) {
    if (blk_shapes[next_blk_shape][0][i] == 1) {
      fill(blk_colors[next_blk_shape + 1]);
    } 
    else {
      fill(blk_colors[0]);
    };
    rect(grid_size * (width + 1 + (i % 4)), grid_size * (i / 4 + 1), grid_size, grid_size);
  };
}

public void keyPressed()
{
  switch (key) {
  case 'z':
  case 'Z':
    move(0,0,3);
    break;
  case 'x':
  case 'X':
    move(0,0,1);
    break;
  case CODED:
    switch (keyCode) {
    case UP:
      move(0,0,1);
      break;
    case DOWN:
      int dy;
      for (dy = 0; dy < height; dy++) {
        if (!can_move(0,dy,0)) break;
      };
      move(0,dy - 1,0);
      break;
    case LEFT:
      move(-1,0,0);
      break;
    case RIGHT:
      move(1,0,0);
      break;
    };
  };
}

public boolean complete_line(int h)
{
  for (int i = 0; i < width; i++) {
    if (grid[h][i] == 0)
      return false;
  };
  return true;
}

public void remove_complete()
{
  int [] ar = new int[height];
  int s = height - 1;
  for (int j = 0; j < height; j++) {
    ar[j] = -1;
  };
  for (int j = height - 1; j >= 0; j--) {
    if (!complete_line(j)) {
      ar[s] = j;
      s--;
    };
  };
  for (int j = height - 1; j >= 0; j--) {
    for (int i = 0; i < width; i++) {
      if (ar[j] == -1) {
        grid[j][i] = 0;
      } 
      else {
        grid[j][i] = grid[ar[j]][i];
      };
    };
  };
}

public int [] rotate90_clockwise(int [] blk)
{
  int [] array = {
    12,8,4,0,
    13,9,5,1,
    14,10,6,2,
    15,11,7,3          };
  int [] result = new int[16];
  for (int i=0; i<16; i++) {
    result[i] = blk[array[i]];
  };
  return result;  
}

public void init_blk_shapes()
{
  blk_shapes[0][0] = blk_shape_I;
  blk_shapes[1][0] = blk_shape_O;
  blk_shapes[2][0] = blk_shape_S;
  blk_shapes[3][0] = blk_shape_Z;
  blk_shapes[4][0] = blk_shape_J;
  blk_shapes[5][0] = blk_shape_L;
  blk_shapes[6][0] = blk_shape_T;
  for (int kind = 0; kind < 7; kind++) {
    for (int r = 1; r < 4; r++) {
      blk_shapes[kind][r] = rotate90_clockwise(blk_shapes[kind][r - 1]);
    };
  };
}

public void init_particles()
{
  for (int j = 0; j < height; j++) {
    for (int i = 0; i < width; i++) {
      particle[j][i] = init_particle(j, i);
    };
  };
  for (int j = 0; j < 4; j++) {
    for (int i = 0; i < 4; i++) {
      particlen[j][i] = init_particle(j + 1, i + width + 1);
    };
  };
};
public int [] init_particle(int j, int i)
{
  int [] array = new int[5];
  array[0] = i * grid_size;
  array[1] = j * grid_size;
  array[2] = PApplet.parseInt(random(-10,10));
  array[3] = -j - 10;
  array[4] = 2 * (height - j);
  return array;
}

public void draw_particles()
{
  for (int j = 0; j < height; j++) {
    for (int i = 0; i < width; i++) {
      draw_particle(particle[j][i], blk_colors[grid[j][i]]);
    };
  };
  for (int j = 0; j < 4; j++) {
    for (int i = 0; i < 4; i++) {
      if (blk_shapes[next_blk_shape][0][j * 4 + i] == 0) {
        draw_particle(particlen[j][i], blk_colors[0]);
      } 
      else {
        draw_particle(particlen[j][i], blk_colors[next_blk_shape + 1]);
      };
    };
  };
}

public void draw_particle(int [] array, int c)
{
  int opq = 100;
  if (array[4] <= 0) {      
    array[0] += array[2];
    array[1] += array[3];
    array[3]++;
    if (array[4] <= -100) {
      opq = 50;
      if (array[4] <= -200) {
        opq = 0;
        if (array[4] <= -300) {
          array[1] -= 20;
          array[3] = 0;
          opq = 100;            
          if (array[4] <= -400) {
            PFont font;
            font = loadFont("AbadiMT-CondensedExtraBold-48.vlw");
            textFont(font,48);
            fill(0);
            text("fin.", display_width / 2 - 50, display_height / 2);
            noLoop();
          };
        };
      };
    };
  };
  array[4]--;
  if (array[0] < 0) {
    array[0] = 0;
    array[2] = -1 * array[2];
  };
  if (array[0] > display_width - grid_size) {
    array[0] = display_width - grid_size;
    array[2] = -1 * array[2];
  };
  if (array[1] > display_height - grid_size) {
    array[1] = display_height - grid_size;
    array[3] = PApplet.parseInt(-0.8f * array[3]);
  }; 
  if (opq == 100) {
    fill(c);
  } else {
    fill(c,opq);
  };
  rect(array[0], array[1], grid_size, grid_size);
}

static public void main(String args[]) {   PApplet.main(new String[] { "p5tetris" });}}